package com.tanchengjin.admin.modules.blog.service.impl;


import com.tanchengjin.admin.exception.ApplicationException;
import com.tanchengjin.admin.model.dao.UserInfoMapper;
import com.tanchengjin.admin.model.dao.UserMapper;
import com.tanchengjin.admin.model.dao.UserOauthMapper;
import com.tanchengjin.admin.model.pojo.User;
import com.tanchengjin.admin.model.pojo.UserInfo;
import com.tanchengjin.admin.model.pojo.UserOauth;
import com.tanchengjin.admin.modules.blog.config.ApiConfig;
import com.tanchengjin.admin.modules.blog.enumerations.OauthType;
import com.tanchengjin.admin.modules.blog.enumerations.SocialEnum;
import com.tanchengjin.admin.modules.blog.enumerations.UserRoleEnum;
import com.tanchengjin.admin.modules.blog.service.UserService;
import com.tanchengjin.admin.modules.blog.utils.JWTUtil;
import com.tanchengjin.admin.modules.blog.validations.MiniProgramAuthenticationValidate;
import com.tanchengjin.admin.modules.blog.vo.MiniProgramUserInfoVO;
import com.tanchengjin.admin.modules.blog.vo.MiniProgramVO;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.*;

@Service("userService")
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private UserOauthMapper userOauthMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private ApiConfig apiConfig;

    @Autowired
    private RestTemplate restTemplate;

    @Value("${app.miniprogram.appid}")
    private String appid;
    @Value("${app.miniprogram.secret}")
    private String secret;


    @Override
    @Transactional
    public User createUserByUsername(String username, String password) {
        User userDB = userMapper.findByUsername(username);
        //用户不存在创建用户
        if (userDB != null) {
            throw new ApplicationException("注册失败！该用户已存在");
        }
        //创建用户表
        User user = new User();
        user.setName(username);
        user.setPassword(passwordEncoder.encode(password));
        user.setStatus((byte) 1);
        user.setRole(UserRoleEnum.NORMAL_ROLE.getName());
        userMapper.insertSelective(user);
        //创建用户信息表
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(user.getId());
        userInfo.setNickname(username);
        createUserInfo(userInfo);
        userDB = user;
        return userDB;
    }

    @Override
    public User findOneById(Long id) {
        return null;
    }

    @Override
    public List<User> getAll() {
        return null;
    }

    private int createUserInfo(UserInfo userInfo) {
        int i = 0;
        i += userInfoMapper.insertSelective(userInfo);
        return i;
    }

    @Override
    public int createUserOauth(long id, String code, OauthType type) {
        int i = 0;
        UserOauth userOauth = new UserOauth();
        userOauth.setUserId(id);
        userOauth.setCode(code);
        userOauth.setOauthType(type.getType());
        i += userOauthMapper.insertSelective(userOauth);
        return i;
    }

    @Override
    public UserOauth findOneByCode(String code) {
        UserOauth userOauth = null;
        userOauth = userOauthMapper.selectByCode(code);
        return userOauth;
    }

    @Override
    @Transactional
    public MiniProgramVO miniProgramAuth(MiniProgramAuthenticationValidate vo) {
        MiniProgramVO miniProgramVO = new MiniProgramVO();
        miniProgramVO.setErrno(1);
        String code = this.getOpenIdByCode(vo.getCode());
//        String code = ""    ;
        if (code == null || code.isEmpty()) throw new ApplicationException("获取Open Id失败");
        UserOauth record = findOneByCode(code);
        User user = new User();
        UserInfo userInfo = new UserInfo();
        if (record == null) {
            //用户不存在，进行注册
            String nickName = (vo.getUserInfo().getNickName() == null || vo.getUserInfo().getNickName().isEmpty()) ? generateStr(8) : vo.getUserInfo().getNickName();
            User byUsername = null;
            String name = "MNPGM_";
            do {
                name = "MNPGM_" + generateStr(8);
                byUsername = userMapper.findByUsername(name);
            } while (byUsername != null);

//            User user = createUserByUsername(name, passwordEncoder.encode(generateStr(32)));
            user.setName(name);
            user.setPassword(passwordEncoder.encode(generateStr(32)));
            user.setRole(UserRoleEnum.NORMAL_ROLE.getName());
            user.setStatus((byte) 1);
            userMapper.insertSelective(user);
            createUserOauth(user.getId(), code, OauthType.MINIPROGRAM);
            //创建用户信息表
            userInfo.setUserId(user.getId());
            userInfo.setNickname(nickName);
            if (vo.getUserInfo().getAvatarUrl() != null && !Objects.equals(vo.getUserInfo().getAvatarUrl(), "")) {
                userInfo.setAvatarUrl(vo.getUserInfo().getAvatarUrl());
            }
            userInfo.setSex(vo.getUserInfo().getGender());
            userInfoMapper.insertSelective(userInfo);
            miniProgramVO.setErrno(0);
        } else {
            //用户存在直接返回信息
            user = userMapper.selectByPrimaryKey(record.getUserId());
            userInfo = userInfoMapper.selectByUserId(record.getUserId());
            miniProgramVO.setErrno(0);

        }
        MiniProgramUserInfoVO miniProgramUserInfoVO = buildData(user, userInfo);
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        stringObjectHashMap.put("userInfo", miniProgramUserInfoVO);
        miniProgramVO.setData(stringObjectHashMap);
        Date date = new Date((System.currentTimeMillis() / 1000) * apiConfig.getJwtAccessTokenExpireTime());
        String token = JWTUtil.sign(apiConfig.getJwtSecret(), user.getUsername(), user.getId(), date);
        miniProgramVO.setAccess_token(token);
        miniProgramVO.setExpire((int) (date.getTime() / 1000));

        return miniProgramVO;
    }

    private MiniProgramUserInfoVO buildData(User user, UserInfo userInfo) {
        MiniProgramUserInfoVO miniProgramUserInfoVO = new MiniProgramUserInfoVO();
        miniProgramUserInfoVO.setName(user.getName());
        miniProgramUserInfoVO.setAvatar(userInfo.getAvatarUrl());
        miniProgramUserInfoVO.setGender(userInfo.getSex());
        return miniProgramUserInfoVO;
    }

    /**
     * 生成随机字符串
     *
     * @param length 长度
     * @return
     */
    private String generateStr(int length) {
        String rdm = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuilder stringBuffer = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int i1 = random.nextInt(rdm.length() - 1);
            char c = rdm.charAt(i1);
            stringBuffer.append(c);
        }
        return stringBuffer.toString();
    }

    /**
     * 通过用户凭证获取微信openId unionid session_key等信息
     *
     * @param appid  小程序 appid
     * @param secret 小程序secret
     * @param code   小程序code wx.login()
     * @return 小程序raw原格式
     */
    public String getOpenIdByCode3(String appid, String secret, String code) {
        String http = String.format(SocialEnum.WX_AUTH_JSCODE.getUrl(), appid, secret, code);
        String forObject = restTemplate.getForObject(http, String.class);
        return forObject;
    }

    public String getOpenIdByCode(String code) {
        String http = String.format(SocialEnum.WX_AUTH_JSCODE.getUrl(), appid, secret, code);
        System.out.println(http);
        String forObject = restTemplate.getForObject(http, String.class);
        JSONObject jsonObject = null;
        jsonObject = JSONObject.fromObject(forObject);
        Iterator keys = jsonObject.keys();
        HashMap<String, Object> o = new HashMap<>();
        while (keys.hasNext()) {
            String key = (String) keys.next();
            Object value = jsonObject.get(key);
            o.put(key, value);
        }
        return o.get("openid").toString();
    }

}
